package com.example.database.controller;

import com.alibaba.fastjson.JSON;
import com.example.database.common.message.ResponseMessage;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;

import java.util.*;

import static org.springframework.data.redis.connection.RedisZSetCommands.*;

@RestController
public class RedisController {
    private Logger logging = LogManager.getLogger();
    @Autowired
    @Qualifier("selfRedisTemplate")
    private RedisTemplate redisTemplate;

    @Autowired
    @Qualifier("selfStringRedisTemplate")
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("strset")
    public String StringSet(@RequestParam String key, @RequestParam String value) {
        redisTemplate.opsForValue().set(key, value);
        value = redisTemplate.opsForValue().get(key).toString();
        return value;
    }

    /**
     * 字符串与散列操作
     *
     * @return
     */

    @GetMapping("stringAndHash")
    public ResponseMessage<String> stringAndHash() {
        redisTemplate.opsForValue().set("key1", "value1");
        redisTemplate.opsForValue().set("int_key", "1");
        stringRedisTemplate.opsForValue().set("int", "1");
        // 使用运算
        stringRedisTemplate.opsForValue().increment("int", 1);

        // 获取底层Jedis连接
        Jedis jedis = (Jedis) stringRedisTemplate.getConnectionFactory().getConnection().getNativeConnection();
        //减1操作 这个命令RedisTemplate不支持，所以我们先获取底层的连接再操作
        jedis.decr("int");

        Map<String, String> hash = new HashMap<>();
        hash.put("field1", "value1");
        hash.put("field2", "value2");
        // 存入一个散列数据类型
        stringRedisTemplate.opsForHash().putAll("hash", hash);
        // 新增一个字段
        stringRedisTemplate.opsForHash().put("hash", "field3", "value3");
        // 绑定散列操作的key，这样可以连续对同一个散列数据类型进行操作
        BoundHashOperations hashOps = stringRedisTemplate.boundHashOps("hash");

        // 删除两个字段
        hashOps.delete("field1", "field2");
        // 新增一个字段
        hashOps.put("filed4", "value5");

        return ResponseMessage.GetMessage("Ok");
    }

    @GetMapping("lsit")
    public ResponseMessage<Object> List() {
        stringRedisTemplate.opsForList().leftPushAll("list1", "v2", "v4", "v6", "v8", "v10");

        stringRedisTemplate.opsForList().rightPushAll("list2", "v1,", "v2", "v3", "v4", "v5", "v6");

        BoundListOperations listOps = stringRedisTemplate.boundListOps("list2");
        String value = listOps.rightPop().toString();
        logging.info(value);
        Object result2 = listOps.index(1);
        logging.info(result2);
        listOps.leftPush("v0");

        long size = listOps.size();
        logging.info(size);

        List elements = listOps.range(0, size - 2);

        return ResponseMessage.GetMessage(elements);
    }

    @GetMapping("set")
    public ResponseMessage<Object> testSet() {
        // 切换数据库
        JedisConnectionFactory factory = (JedisConnectionFactory) stringRedisTemplate.getConnectionFactory();
        factory.setDatabase(2);
        stringRedisTemplate.setConnectionFactory(factory);
        // 只会有5个插入成功
        stringRedisTemplate.opsForSet().add("set1", "v1", "v1", "v2", "v3", "v4", "v5");
        stringRedisTemplate.opsForSet().add("set2", "v2", "v4", "v6", "v8");
        BoundSetOperations setOps = stringRedisTemplate.boundSetOps("set1");

        setOps.add("v6", "v7");
        setOps.remove("v1", "v7");

        Set set1 = setOps.members();
        logging.info("set1 Value" + set1);
        long size = setOps.size();
        // 求交集
        Set inter = setOps.intersect("set2");
        logging.info("intersect value:" + JSON.toJSONString(inter));
        // 求差集
        Set diff = setOps.diff("set2");
        logging.info("diff value" + JSON.toJSONString(diff));

        // 求差集，并且用新集合diff保存
        setOps.diffAndStore("set2", "diff");

        // 求并集
        Set union = setOps.union("set2");
        logging.info("union value:" + JSON.toJSONString(union));
        setOps.unionAndStore("set2", "union");

        return ResponseMessage.GetMessage("");
    }

    @GetMapping("zset")
    public ResponseMessage<Object> ZSet() {
        Set<ZSetOperations.TypedTuple<String>> typedTupleSet = new HashSet<>();
        for (int i = 1; i <= 9; i++) {
            double score = i + 0.1;
            ZSetOperations.TypedTuple<String> typedTuple = new DefaultTypedTuple<>("value" + i, score);
            typedTupleSet.add(typedTuple);
        }
        // 往有序集合插入元素
        stringRedisTemplate.opsForZSet().add("zset1", typedTupleSet);
        BoundZSetOperations zsetOps = stringRedisTemplate.boundZSetOps("zset1");
        zsetOps.add("value10", 0.26);
        Set<String> setRange = zsetOps.range(1, 6);

        logging.info("SetRange:" + JSON.toJSONString(setRange));
        // 按分数 排序获取有序集合
        Set<String> setScore = zsetOps.rangeByScore(0.2, 0.6);

        logging.info("setScore" + JSON.toJSONString(setScore));

        // 定义值范围
        Range range = new Range();
        // 大于 value3
        range.gt("value3");
        range.lte("value8");
        // 按值排序，请注意这个排序是按字符串排序
        Set<String> setLex = zsetOps.rangeByLex(range);

        logging.info("setLex:" + JSON.toJSONString(setLex));

        zsetOps.remove("value9", "value2");

        double score = zsetOps.score("value8");

        // 在下标区间按分数排序 同时返回 value 和score

        Set<TypedTuple<String>> rangeSet = zsetOps.rangeWithScores(1, 6);
        logging.info("range by index :" + JSON.toJSONString(rangeSet));
        Set<TypedTuple<String>> scoreSet = zsetOps.rangeByScoreWithScores(1, 6);
        logging.info("range by score index:" + JSON.toJSONString(scoreSet));
        // 从大到小排序
        Set<String> reverseSet = zsetOps.reverseRange(2, 8);
        logging.info(" reverse :" + JSON.toJSONString(reverseSet));
        return ResponseMessage.GetMessage(reverseSet);

    }

}
